﻿using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Nature
{
    /// <summary>
    /// Represents a read-only matrix of elements
    /// </summary>
    /// <typeparam name="T">The type of elements in the matrix.</typeparam>
    [DebuggerDisplay("[{Length}][...]")]
    [Serializable]
    public struct ReadOnlyMatrix<T> : IEnumerable<ReadOnlyArray<T>>
    {
        #region Private Fields
        [DebuggerBrowsable(DebuggerBrowsableState.RootHidden | DebuggerBrowsableState.Never)]
        private T[][] m_matrix;
        #endregion

        /// <summary>
        /// Initializes a new instance of the System.ReadOnlyMatrix&lt;T&gt; structure to the specified matrix of elements.
        /// </summary>
        /// <param name="matrix">The type of elements in the matrix</param>
        [DebuggerStepThrough()]
        public ReadOnlyMatrix(T[][] matrix)
        {
            m_matrix = matrix;
        }

        /// <summary>
        /// Implicitly convertes the given matrix of elements into the ReadOnlyMatrix object
        /// </summary>
        /// <param name="matrix">Matrix of elements</param>
        /// <returns>ReadOnlyMatrix object</returns>
        [DebuggerStepThrough()]
        public static implicit operator ReadOnlyMatrix<T>(T[][] matrix)
        {
            return new ReadOnlyMatrix<T>(matrix);
        }

        /// <summary>
        /// Gets the value of the element of the ReadOnlyArray type at a specific position in the ReadOnlyMatrix
        /// </summary>
        /// <param name="i">The zero-based index of the value to get.</param>
        /// <returns>The element of the ReadOnlyArray type at position index.</returns>
        [DebuggerHidden()]
        public ReadOnlyArray<T> this[int i]
        {
            get { return m_matrix[i]; }
        }

        /// <summary>
        /// Gets a 32-bit integer that represents the total number of rows in this matrix
        /// </summary>
        [DebuggerHidden()]
        public int Length
        {
            get { return m_matrix.Length; }
        }

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal T[][] Data { get { return m_matrix; } }

        #region IEnumerable<ReadOnlyArray<T>> Members

        /// <summary>
        /// Returns an System.Collections.Generic.IEnumerator(T) for the ReadOnlyMatrix.
        /// </summary>
        /// <returns>An System.CollectionsGeneric.IEnumerator(T) for the ReadOnlyMatrix.</returns>
        IEnumerator<ReadOnlyArray<T>> IEnumerable<ReadOnlyArray<T>>.GetEnumerator()
        {
            for (int i = 0; i < Length; ++i)
            {
                yield return new ReadOnlyArray<T>(m_matrix[i]);
            }
        }

        #endregion

        #region IEnumerable Members

        /// <summary>
        /// Returns an System.Collections.IEnumerator for the ReadOnlyMatrix.
        /// </summary>
        /// <returns>An System.Collections.IEnumerator for the ReadOnlyMatrix.</returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            for (int i = 0; i < Length; ++i)
            {
                yield return new ReadOnlyArray<T>(m_matrix[i]);
            }
        }

        #endregion
    }
}
